﻿Shader "Cartoon/CelShader"
{
    Properties
    {
        _BaseMap("BaseMap", 2D) = "white" {}

        [Header(Outline)]
        _OutlineColor("OutlinneColor",Color) = (0,0,0,1)
        _OutlineWidth("OutlineWidth",Range(0,1)) = 0.1
        _UniformWidth("UniformWidth",Range(0,1)) = 0.1 //

        // [Header(Color)]
        [Header(Diffuse)]
        _HColor("Highlight Color",Color) = (1,1,1,1)   //亮部颜色
		_SColor("shadow Color",Color) = (0.5,0.5,0.5,1)  //阴影部分颜色
        _RampThreshold("RampThreshold",Range(0,1)) = 0.8		//明暗边界阀值
        _RampSmooth("RampSmooth",Range(0,1)) = 0.1				// 明暗边界平滑过渡

        //ramMap
        [Header(RamMap)]
        [Toggle]_RAMPTEXT("_RAMPTEXT_ON",int) = 0
        _ShadowRampMap("ShadowRamMap",2D) = "white"{}
        //阴影
        [Header(ShadowMask)]
        [Toggle]_SHADOEWMASK("_SHADOEWMASK_ON",int) = 0
        _ShadowMask("ShadowMask",2D) = "white"{}

        [Header(Specular)]
        _Specular("高光强度(X) 扩散度(Y) 高光柔化(Z)",vector) = (1,1,0,1)
        // 高光贴图
        _SpecularMask("SpecularMask",2D) = "black"{}
        [Toggle]_MATCAP("_MATCAP_ON",int) = 1
        _MatCap("MatCap",2D) = "white" {}
        _SpecularAO("SpecularAO",Range(0,1)) = 0.1

        //外发光
        [Header(Rim)]
        _FresnelColor("FreshelColor",Color) = (1,1,1,1)
        _Fresnel("外发光强度(X)扩散度(Y)柔和度(Z)透明度(W)",vector) = (1,1,0,0)
    }

    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        // 描边
        Pass
        {
            Cull Front
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float3 normal : NORMAL;
                float4 color  : COLOR;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;

            float _OutlineWidth;
            float4 _OutlineColor;
            float _UniformWidth;

            v2f vert (appdata v)
            {
                v2f o;
                // 描边1 
                // 描边本身的宽度是不会变化的，但是随着时距会有近大远小的视觉效果
                // 如果需要保持不变，则需要根据时距的变化加上对应的值，则原来宽度+视距的长度，可表示效果
                // 求出相机与顶点之间的距离
                float3 worldPos = mul(unity_ObjectToWorld,v.vertex.xyz);
                float3 distance = length(_WorldSpaceCameraPos - worldPos);

                //distance = 1 时，保持近大远小
                //distance = distance 时，保持粗细不变
                // _UniformWidth = 0时，使用默认近大远小 ，否则保持粗细不变
                distance = lerp(1,distance,_UniformWidth);
                float3 pos = v.vertex.xyz;
                float3 width = normalize(v.normal) * _OutlineWidth *0.01;
                width *= distance;
                width *= v.color.a;  //模型的顶点色 a 控制模型描边的粗细
                v.vertex.xyz += width;
                
                o.vertex = UnityObjectToClipPos(v.vertex);

                // 描边2 （随着镜头拉远会随之变大 视觉上看起来）
                // // 缩小描边大小(0~1范围会很大)
				// float outlineVar = _OutlineWidth * 0.01;  
				// // 齐次裁剪空间下的法线
				// float3 clipNormal = mul((float3x3) UNITY_MATRIX_MVP, v.normal);
                // // 沿法线方向挤出
				// o.vertex.xy += normalize(clipNormal.xy)/normalize(_ScreenParams.xy) * outlineVar * o.vertex.w * 2;
                
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                return _OutlineColor;
            }
            ENDCG
        }

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile SHADOWS_SCREEN
            // make fog work
            #pragma multi_compile_fog
            // ramp 的开关 
            #pragma multi_compile _ _RAMPTEXT_ON
            // 阴影贴图 
            #pragma multi_compile _ _SHADOEWMASK_ON
            // matcap 的开关 
            #pragma multi_compile _ _MATCAP_ON
            #include "UnityCG.cginc"
            #include "AutoLight.cginc"
            #include "Lighting.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                float4 pos : SV_POSITION;
                float3 worldNormal : TEXCOORD1;
                float3 worldPos : TEXCOORD2;
                float2 matcapUV : TEXCOORD3;
                // 接收的阴影坐标(做自阴影)
                SHADOW_COORDS(4)
            };

            // 基础纹理
            sampler2D _BaseMap;
            float4 _BaseMap_ST;

            // 漫反射亮暗面颜色
            float4 _HColor;
            float4 _SColor;

            // ramMap
            #if _RAMPTEXT_ON
                sampler2D _ShadowRampMap;
            #else
                float _RampThreshold;
                float _RampSmooth;
            #endif
            
            // mask (阴影)
            sampler2D _ShadowMask;
            sampler2D _MatCap;

            // 高光贴图
            sampler2D _SpecularMask;

            float4 _Specular;
            float _SpecularAO;
            float4 _Fresnel,_FresnelColor;

            v2f vert (appdata v)
            {
                v2f o = (v2f)0;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _BaseMap);
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld,v.vertex);
                
                #if _MATCAP_ON
                    // 世界空间转到观察空间
                    float3 viewNormal = mul((float3x3)UNITY_MATRIX_V, o.worldNormal);
                    o.matcapUV = viewNormal.xy * 0.5 + 0.5;
                #endif
                TRANSFER_SHADOW(o);
                UNITY_TRANSFER_FOG(o,o.pos);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 baseMap = tex2D(_BaseMap, i.uv);

                // 入射光
                float3 lightDirection = normalize(_WorldSpaceLightPos0.xyz);
                // 法线
                float3 normalDirection = normalize(i.worldNormal);
                // 观察方向
                float3 viewDirection = normalize(_WorldSpaceCameraPos.xyz - i.worldPos);
                // 半角向量
                float3 halfDirection = normalize(lightDirection + viewDirection);
                // 光照颜色
                float3 lightColor = _LightColor0.rgb; 	

                //=============== 漫反射 
                // lamber
                float NdotL = dot(normalDirection,lightDirection) * 0.5 + 0.5;

                // 使用rampMap 或者 smoothstep 做过渡
                #if _RAMPTEXT_ON
                    fixed3 ramp = tex2D(_ShadowRampMap, fixed2(NdotL,NdotL));
                #else
                    fixed3 ramp = smoothstep(_RampThreshold - _RampSmooth * 0.5,_RampThreshold + _RampSmooth * 0.5,NdotL);
                #endif
                //阴影部分颜色
				fixed3 SColor = lerp(_HColor,_SColor,_SColor.a);
				//亮部颜色
				fixed3 HColor = _HColor.rgb;
                ramp = lerp(SColor.rgb,HColor.rgb,ramp);


                // 反射颜色
                fixed3 diffuse = lightColor * ramp;

                //=============== 阴影
                #if _SHADOEWMASK_ON
                    fixed4 shadowMask = tex2D(_ShadowMask, i.uv);
                    shadowMask = shadowMask *0.5 + 0.5;
                #else
                    fixed4 shadowMask = fixed4(1,1,1,1);
                #endif
                // 获取当前的阴影(unity内置函数)
                fixed shadow = SHADOW_ATTENUATION(i);
                shadow = saturate(shadow+0.5);
                //=============== 高光 
                // BlinnePhong
                fixed NdotH = dot(normalDirection,halfDirection);
                fixed4 specular = _Specular.x * pow(NdotH,_Specular.y);
                //specular = smoothstep(0.5,0.5+_Specular.z,specular);

                fixed4 specularMask = tex2D(_SpecularMask, i.uv);
                specular *= specularMask;
                specular *= _Specular.w;

                // matcap
                #if _MATCAP_ON
                    fixed3 matcapSpecular = tex2D(_MatCap,i.matcapUV).rgb * _SpecularAO;
                #else
                    fixed3 matcapSpecular = fixed3(0,0,0);
                #endif
                specular.rgb += matcapSpecular;

                //=============== 外发光 菲涅尔（fresnel）
                
                fixed NdotV = 1 - saturate(dot(normalDirection,viewDirection));
                fixed4 fresnel = _Fresnel.x * pow(NdotV,_Fresnel.y);
                fresnel *= _FresnelColor;
                fresnel *= _Fresnel.w;

                //=============== 最终颜色
                fixed3 finalColor = baseMap;
                finalColor *= diffuse;
                finalColor *= shadowMask.rgb;
                finalColor += specular + fresnel;
                finalColor *= shadow;
                fixed4 finalRGBA = fixed4(finalColor,1);

                UNITY_APPLY_FOG(i.fogCoord, finalRGBA);
                return finalRGBA;
            }
            ENDCG
        }
        
    }
    FallBack "Diffuse"
}
